package xyz.scootaloo.oj.ds.helper;

import xyz.scootaloo.oj.ds.ListNode;
import xyz.scootaloo.oj.ds.TreeNode;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author flutterdash@qq.com
 * @since 2021/3/23 22:57
 */
public class CollectionBuilder {

    public static int[] intArr(int ... integers) {
        return integers;
    }

    public static List<Integer> list(int ... integers) {
        return Arrays.stream(integers).boxed().collect(Collectors.toList());
    }

    public static ListNode getHeadOfList(ListNode ... nodes) {
        ListNode head = nodes[0];
        ListNode pointer = head;
        for (int i = 1; i<nodes.length; i++) {
            pointer.next = nodes[i];
            pointer = pointer.next;
        }
        return head;
    }

    public static TreeBuilder initTree() {
        return new TreeBuilder();
    }

    public static ListNode initNode(int ... data) {
        ListNode root = null;
        if (data == null || data.length == 0)
            return root;

        root = new ListNode(data[0]);
        ListNode tmp = root;
        for (int i = 1; i<data.length; i++) {
            tmp.next = new ListNode(data[i]);
            tmp = tmp.next;
        }

        return root;
    }

    public static TreeNode list2tree(List<Integer> nodeList) {
        TreeNode root = new TreeNode(nodeList.get(0));
        list2treeCore(nodeList, root, 1);
        return root;
    }

    private static void list2treeCore(List<Integer> nodeList,  TreeNode node, int offset) {
        if (offset < nodeList.size() && nodeList.get(offset) != null) {
            node.left = new TreeNode(nodeList.get(offset));
            list2treeCore(nodeList, node.left, offset*2 + 1);
        }
        if (offset < nodeList.size() && nodeList.get(offset + 1) != null) {
            node.right = new TreeNode(nodeList.get(offset + 1));
            list2treeCore(nodeList, node.right,  (offset + 1)*2 + 1);
        }
    }

    public static class TreeBuilder {

        private final ArrayList<Integer> nodeList;
        private int offset;
        private int level;

        public TreeBuilder() {
            nodeList = new ArrayList<>();
            offset = 0;
            level = 0;
        }

        public TreeBuilder setRoot(int val) {
            if (nodeList.size() == 0) {
                nodeList.add(val);
                level = 1;
            } else {
                nodeList.set(0, val);
            }
            return this;
        }

        /**
         *       tree:        layer    size
         *         5            1        1
         *       /   \
         *      2     8         2        2
         *     / \   / \
         *    1   3 6   9       3        4
         *      ... ...
         *                      4        8
         *
         *        layer[i].size == (size - 1)^2
         *
         * @param values 要被添加的内容
         * @return 修剪尺寸后的列表
         */
        public TreeBuilder addLevel(Integer ... values) {
            // 每次偏移量提升一倍
            level += 1;
            offset = offset * 2 + 1;
            int maxNum = (int) Math.pow(2,  level - 1);

            if (values.length > maxNum) {
                System.out.println("第" + level + "层有多余的数据，将被修剪");
            }

            // 填充默认数据
            for (int i = 0; i<maxNum; i++)
                nodeList.add(null);

            for (int i = 0; i<maxNum; i++) {
                if (i > values.length - 1)
                    break;
                nodeList.set(offset + i, values[i]);
            }
            return this;
        }

        public TreeNode build() {
            return list2tree(this.nodeList);
        }
    }

}
